"""
AI模板管理系统

统一管理AI提示词模板，支持模板变量替换和多种报告类型。
提供模板的加载、渲染和缓存功能。
"""

from typing import Dict, Any, Optional
import logging
from dataclasses import dataclass
from abc import ABC, abstractmethod
import json
import os

logger = logging.getLogger(__name__)


@dataclass
class TemplateContext:
    """模板上下文数据"""
    report_type: str
    data: Dict[str, Any]
    metadata: Dict[str, Any]
    
    def get(self, key: str, default: Any = None) -> Any:
        """获取上下文数据"""
        if key in self.data:
            return self.data[key]
        if key in self.metadata:
            return self.metadata[key]
        return default


class BaseTemplate(ABC):
    """模板基类"""
    
    def __init__(self, template_id: str, name: str):
        self.template_id = template_id
        self.name = name
    
    @abstractmethod
    def render(self, context: TemplateContext) -> str:
        """渲染模板"""
        pass
    
    def validate_context(self, context: TemplateContext) -> bool:
        """验证上下文数据是否完整"""
        return True


class StringTemplate(BaseTemplate):
    """字符串模板"""
    
    def __init__(self, template_id: str, name: str, template_string: str, required_vars: list = None):
        super().__init__(template_id, name)
        self.template_string = template_string
        self.required_vars = required_vars or []
    
    def render(self, context: TemplateContext) -> str:
        """渲染字符串模板"""
        if not self.validate_context(context):
            raise ValueError(f"模板{self.template_id}的上下文数据不完整")
        
        # 准备模板变量
        template_vars = {
            **context.data,
            **context.metadata,
            'report_type': context.report_type
        }
        
        try:
            return self.template_string.format(**template_vars)
        except KeyError as e:
            raise ValueError(f"模板{self.template_id}缺少必需变量: {e}")
    
    def validate_context(self, context: TemplateContext) -> bool:
        """验证上下文数据"""
        for var in self.required_vars:
            if context.get(var) is None:
                logger.error(f"模板{self.template_id}缺少必需变量: {var}")
                return False
        return True


class FileTemplate(BaseTemplate):
    """文件模板"""
    
    def __init__(self, template_id: str, name: str, file_path: str, required_vars: list = None):
        super().__init__(template_id, name)
        self.file_path = file_path
        self.required_vars = required_vars or []
        self._template_content = None
    
    def _load_template(self) -> str:
        """加载模板文件"""
        if self._template_content is None:
            try:
                with open(self.file_path, 'r', encoding='utf-8') as f:
                    self._template_content = f.read()
            except FileNotFoundError:
                raise FileNotFoundError(f"模板文件不存在: {self.file_path}")
            except Exception as e:
                raise Exception(f"加载模板文件失败: {e}")
        
        return self._template_content
    
    def render(self, context: TemplateContext) -> str:
        """渲染文件模板"""
        if not self.validate_context(context):
            raise ValueError(f"模板{self.template_id}的上下文数据不完整")
        
        template_content = self._load_template()
        
        # 准备模板变量
        template_vars = {
            **context.data,
            **context.metadata,
            'report_type': context.report_type
        }
        
        try:
            return template_content.format(**template_vars)
        except KeyError as e:
            raise ValueError(f"模板{self.template_id}缺少必需变量: {e}")
    
    def validate_context(self, context: TemplateContext) -> bool:
        """验证上下文数据"""
        for var in self.required_vars:
            if context.get(var) is None:
                logger.error(f"模板{self.template_id}缺少必需变量: {var}")
                return False
        return True


class TemplateManager:
    """模板管理器"""
    
    def __init__(self):
        self.templates: Dict[str, BaseTemplate] = {}
        self.logger = logging.getLogger(self.__class__.__name__)
        self._initialize_default_templates()
    
    def register_template(self, template: BaseTemplate):
        """注册模板"""
        self.templates[template.template_id] = template
        self.logger.info(f"注册模板: {template.template_id} - {template.name}")
    
    def get_template(self, template_id: str) -> Optional[BaseTemplate]:
        """获取模板"""
        return self.templates.get(template_id)
    
    def render_template(self, template_id: str, context: TemplateContext) -> str:
        """渲染模板"""
        template = self.get_template(template_id)
        if template is None:
            raise ValueError(f"模板不存在: {template_id}")
        
        return template.render(context)
    
    def list_templates(self) -> Dict[str, str]:
        """列出所有模板"""
        return {tid: template.name for tid, template in self.templates.items()}
    
    def _initialize_default_templates(self):
        """初始化默认模板"""
        # 工人报告模板
        worker_template = StringTemplate(
            template_id='worker_report',
            name='工人工作分析报告',
            template_string=self._get_worker_report_template(),
            required_vars=['member_name', 'depart_name', 'start_time', 'end_time', 'total_days',
                          'base_csv', 'work_csv', 'no_work_csv', 'clock_in_csv']
        )
        self.register_template(worker_template)
        
        # 设备报告模板
        equipment_template = StringTemplate(
            template_id='equipment_report',
            name='设备工作分析报告',
            template_string=self._get_equipment_report_template(),
            required_vars=['member_name', 'start_time', 'end_time', 'total_days',
                          'equipment_csv', 'iot_run_csv', 'equipment_count']
        )
        self.register_template(equipment_template)
        
        # 项目报告模板
        project_template = StringTemplate(
            template_id='project_report',
            name='项目设备分析报告',
            template_string=self._get_project_report_template(),
            required_vars=['member_name', 'project_name', 'start_time', 'end_time', 'total_days',
                          'equipment_csv', 'iot_run_csv', 'equipment_count']
        )
        self.register_template(project_template)
    
    def _get_worker_report_template(self) -> str:
        """获取工人报告模板"""
        return """
这是一些工人的工作数据。请帮我分析一下他们的工作情况。你现在要做的是帮我输出一份用于物业保洁公司的日常工人工作管理整改数据分析报告。

请严格的计算，不要瞎说八道，也不需要思考很长的逻辑链，你最需要做到的是精确计算，并且给出严谨的回答，但在输出结果中不需要说明这些也不需要说你是根据什么来做的。我只要你输出结果。

这是基础数据表：{base_csv}
这是工作数据表：{work_csv}
这是无工作记录表：{no_work_csv}
这是出勤统计表：{clock_in_csv}

两个表通过IMEI进行链接，展示分析完的结果。我要用做物业公司开会报告分析。

标题为《{member_name}_{depart_name} {start_time:%Y年%m月%d日} 至 {end_time:%Y年%m月%d日} 工人工作分析报告》

展示内容需要进行美化，输出完整的html格式，考虑宽度是A4输出因为我最终要输出到pdf里，表格内容都要居中，表头文字要加粗，整体样式要一致。

如果是纯文字的部分内容要用合适的html展示方式来输出，标题和内容要分清，可以生成一行一列的表格，来展示标题和内容。

所有结果你经过严格计算，请调用你的统计计算能力，这个时候你是一名严格的数据统计工作者，不要产生幻觉。输出时再考虑一次数据的准确性。

不要给我XX之类的语言，排名时如果只有一个项目，请一起说明不要计算数据为0的，避免无效无参考价值的数据。

分析内容包括：
第一部分：整体出勤率分析 - 总天数为{total_days}天
第二部分：工作时间分析和排名
第三部分：达标情况分析（8000步数和300分钟工作时间为达标标准）
第四部分：问题员工识别和分析
第五部分：管理和整改建议

工作时间的单位是分钟，输出的结果换算成小时和分钟的组合。也不需要告诉我你如何思考，你输出的结果必须是不带任何AI味道的。

结果不是给我看的，是直接给客户看的所以不要有（注：XXX）什么的内容或者你要怎么怎么做。都和我没有关系。

一定不要有任何中间性的文字输出，你输出的任何文字都是面向客户的，是生产环境。
"""
    
    def _get_equipment_report_template(self) -> str:
        """获取设备报告模板"""
        return """
这是一些清洁设备的工作数据。请帮我分析一下他们的工作情况。你现在要做的是帮我输出一份用于物业保洁公司的日常清洁设备管理整改数据分析报告。

请严格的计算，不要瞎说八道，也不需要思考很长的逻辑链，你最需要做到的是精确计算，并且给出严谨的回答，但在输出结果中不需要说明这些也不需要说你是根据什么来做的。我只要你输出结果。

这是工作数据表：{iot_run_csv}
设备基础数据表：{equipment_csv}

两个表通过IMEI进行链接，展示分析完的结果。需要展示设备信息的时候用设备名称alias，展示工作时间的同时展示时间乘以work_amount，单位是work_unit。

我要用做物业公司开会报告分析。

标题为《{member_name} {start_time:%Y年%m月%d日} 至 {end_time:%Y年%m月%d日} 清洁设备工作分析报告》

展示内容需要进行美化，输出完整的html格式，考虑宽度是A4输出因为我最终要输出到pdf里，表格内容都要居中，表头文字要加粗，整体样式要一致。

如果是纯文字的部分内容要用合适的html展示方式来输出，标题和内容要分清，可以生成一行一列的表格，来展示标题和内容。

所有结果你经过严格计算，请调用你的统计计算能力，这个时候你是一名严格的数据统计工作者，不要产生幻觉。输出时再考虑一次数据的准确性。

不要给我XX之类的语言，排名时如果只有一个项目，请一起说明不要计算数据为0的，避免无效无参考价值的数据。

以下生成的内容每一项我要求展示排名的地方如果数量不够三就只展示排名，这个你要有逻辑要合理。

第一部分是他们的整体项目出勤率
总设备数{equipment_count}台，应出勤天数为{total_days}天
根据有出勤统计表来
根据出勤统计表，将人数和天数进行相乘得出项目总应出勤天数，和实际出勤天数，得出项目总出勤率
按这个逻辑再统计每个项目的总应出勤天数和实际出勤天数，展示并相除得出设备出勤率并展示
完全缺勤设备是没有在工作数据表里出现过却在总设备里面的
设备未出勤的天数即为闲置天数，有出勤的设备中，展示闲置率的前三名
以下关于时间排名的均不算0小时0分钟的

第二部分是他们每个大区平均有效工作时间，工作面积，以及排名
第三部分是他们的每个大区各项目各项目平均有效工作时间，分别展示，还要用文字说明，随时间变化的趋势
第四部分是每个大区的项目日均工作时间前三名和最后三名
第五部分是以2个小时为达标时间，每个项目的达标率是多少，以及他们的排名
第六部分是管理和整改建议。假如你是一名物业保洁管理专家。根据以上数据对项目进行可落地的管理整改建议，并给出原因。建议要求针对数据。不要笼统。比如对某人某岗位进行整改和处理，针对特别异常的数据要特别说明用红字标出

根据一些数据随时间的变化趋势给出一些可能性分析，并给我下一步公司针对设备管理的建议
合理性分析，并给出一些建议。

工作时间的单位是分钟，输出的结果换算成小时和分钟的组合。也不需要告诉我你如何思考，你输出的结果必须是不带任何AI味道的。

结果不是给我看的，是直接给客户看的所以不要有（注：XXX）什么的内容或者你要怎么怎么做。都和我没有关系。

一定不要有任何中间性的文字输出，你输出的任何文字都是面向客户的，是生产环境，最后也不需要画蛇添足给我解释这些数据怎么得出的，可以做什么，一个多余的字都不要有，一个多余的字都不要有。
"""
    
    def _get_project_report_template(self) -> str:
        """获取项目报告模板"""
        return """
这是一些清洁设备的工作数据。请帮我分析一下他们的工作情况。你现在要做的是帮我输出一份用于物业保洁公司的日常清洁设备管理整改数据分析报告。

请严格的计算，不要瞎说八道，也不需要思考很长的逻辑链，你最需要做到的是精确计算，并且给出严谨的回答，但在输出结果中不需要说明这些。

这是工作数据表：{iot_run_csv}
设备基础数据表：{equipment_csv}

两个表通过IMEI进行链接，展示分析完的结果。需要展示设备信息的时候用设备名称alias，展示工作时间的同时展示时间乘以work_amount，单位是work_unit。

我要用做物业公司开会报告分析。

标题为《{member_name}-{project_name} {start_time:%Y年%m月%d日} 至 {end_time:%Y年%m月%d日} 清洁设备工作分析报告》

展示内容需要进行美化，输出完整的html格式，考虑宽度是A4输出因为我最终要输出到pdf里，表格内容都要居中，表头文字要加粗，整体样式要一致。

如果是纯文字的部分内容要用合适的html展示方式来输出，标题和内容要分清，可以生成一行一列的表格，来展示标题和内容。

所有结果你经过严格计算，请调用你的统计计算能力，这个时候你是一名严格的数据统计工作者，不要产生幻觉。输出时再考虑一次数据的准确性。

不要给我XX之类的语言。

第一部分是他们的项目设备出勤率
总设备数{equipment_count}台，应出勤天数为{total_days}天
根据有出勤统计表来
根据出勤统计表，将人数和天数进行相乘得出项目总应出勤天数，和实际出勤天数，得出项目总出勤率
按这个逻辑再统计项目的总应出勤天数和实际出勤天数，展示并相除得出设备出勤率并展示
完全缺勤设备是没有在工作数据表里出现过却在总设备里面的
设备未出勤的天数即为闲置天数，有出勤的设备中，展示闲置率的前三名
以下关于时间排名的均不算0小时0分钟的

第二部分是项目平均有效工作时间，工作面积，以及排名
第三部分是项目平均有效工作时间，随时间变化的趋势
第四部分是以2个小时为达标时间，每台设备的达标率是多少，以及他们的排名
第五部分是管理和整改建议。假如你是一名物业保洁管理专家。根据以上数据对项目进行可落地的管理整改建议，并给出原因。建议要求针对数据。不要笼统。比如对某人某岗位进行整改和处理，根据一些数据随时间的变化趋势给出一些可能性分析

合理性分析，并给出一些建议。

工作时间的单位是分钟，输出的结果换算成小时和分钟的组合。也不需要告诉我你如何思考，你输出的结果必须是不带任何AI味道的。

结果不是给我看的，是直接给客户看的所以不要有（注：XXX）什么的内容或者你要怎么怎么做。都和我没有关系。
"""


# 全局模板管理器实例
_global_template_manager: Optional[TemplateManager] = None


def get_template_manager() -> TemplateManager:
    """获取全局模板管理器实例"""
    global _global_template_manager
    if _global_template_manager is None:
        _global_template_manager = TemplateManager()
    return _global_template_manager


def set_template_manager(manager: TemplateManager):
    """设置全局模板管理器实例"""
    global _global_template_manager
    _global_template_manager = manager